﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ZoomEngine.Animation
{
    // An Animation<T> is a clock that produces a value of type T
    // on each tick of the clock.
    public abstract class Animation<T> : Clock
    {
        public Animation(ClockManager manager) :
            base(manager)
        { 
        }

        protected override void OnTicked(float progress)
        {
            var progressTransform = ProgressTransform;            
            if (progressTransform != null)
            {
                progress = progressTransform(progress);
            }

            CurrentValue = GetCurrentValue(progress);
            OnApply(CurrentValue);
        }

        protected virtual void OnApply(T currentValue)
        {
            var apply = Apply;
            if (apply != null)
            {
                apply(currentValue);
            }
        }

        protected abstract T GetCurrentValue(float progress);

        public Func<float, float> ProgressTransform { get; set; }
        public Action<T> Apply { get; set; }
        public T CurrentValue { get; private set; }
 }

    public abstract class FromToAnimation<T> : Animation<T>
    {
        public FromToAnimation(ClockManager manager) :
            base(manager)
        { 
        }

        protected override T GetCurrentValue(float progress)
        {
            var interpolate = Interpolate;
            if (interpolate != null)
            {
                return interpolate(_from, _to, progress);
            }

            return Lerp(_from, _to, progress);
        }

        protected override void OnBegin()
        {
            if (Begin != null)
            {
                Begin(this, EventArgs.Empty);
            }

            base.OnBegin();
        }

        protected override void OnCompleted()
        {
            if (Complete != null)
            {
                Complete(this, EventArgs.Empty);
            }

            base.OnCompleted();
        }

        protected override void OnLooped()
        {
            if (Looped != null)
            {
                Looped(this, EventArgs.Empty);
            }

            base.OnLooped();
        }

        protected abstract T Lerp(T from, T to, float progress);

        public event EventHandler Begin;
        public event EventHandler Complete;
        public event EventHandler Looped;
        public Func<T, T, float, T> Interpolate { get; set; }
        public T From { get { return _from; } set { _from = value; } }
        public T To { get { return _to; } set { _to = value; } }

        T _from;
        T _to;
    }
}
